package org.xin.framework.base.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Bean;
import org.xin.common.util.XinUtil;
import org.xin.framework.base.mapper.IBaseMapper;
import org.xin.framework.base.pojo.form.SearchForm;
import org.xin.framework.base.service.IBaseService;
import org.xin.framework.config.PageHelper;
import org.xin.framework.constant.SearchFormParameter;
import org.xin.framework.constant.SearchFormType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;

/**
 * @author ：xin
 * @date ：Created in 2021/9/29
 * @desc <p>  </p>
 * @modified By：$
 * @version: $
 */
public class IBaseServiceImpl <DOMAIN, M extends IBaseMapper<DOMAIN>> extends ServiceImpl<M, DOMAIN> implements IBaseService<DOMAIN> {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 当前泛型真实类型的Class
     */

    protected Class<DOMAIN> domainClass;



    /**
     * 实体类的父类Class
     */
    protected Class<?> baseEntityClass;

//    protected Query<?, DOMAIN, M> query;

    /**
     * @desc <p> queryWrapper </p>
     * @author xin
     * @date 2021/10/1
     */
    protected QueryWrapper<DOMAIN> queryWrapper;

    /**
     * @desc <p> lambdaQueryWrapper </p>
     * @author xin
     * @date 2021/10/1
     */
    protected LambdaQueryWrapper<DOMAIN> lambdaQueryWrapper;


    public IBaseServiceImpl() {
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        domainClass = (Class<DOMAIN>) pt.getActualTypeArguments()[0];
        baseEntityClass = domainClass.getSuperclass();
    }

    @Override
    public List<DOMAIN> children(String parentId) {
        Method method = ReflectUtil.getMethod(domainClass, "getParentId");
        if (XinUtil.isNull(method)) {
            return null;
        }
        queryWrapper().eq("parentId", parentId);
        return baseMapper.selectList(queryWrapper);
    }

//    @Cacheable(value = "search", key = "#clazz.getName()")
    @Override
    public PageHelper<DOMAIN> search(JSONObject object, Class<?> clazz) {
        return search(object);
    }

    @Override
    public PageHelper<DOMAIN> search(JSONObject object) {
        Integer page = 0, limit = 10;
        if (XinUtil.noNull(object.get(SearchFormParameter.PAGE_NUM))) {
            page = Convert.toInt(object.get(SearchFormParameter.PAGE_NUM));
        }
        if (XinUtil.noNull(object.get(SearchFormParameter.PAGE_SIZE))) {
            limit = Convert.toInt(object.get(SearchFormParameter.PAGE_SIZE));
        }
        if (XinUtil.isNull(object)) {
            return page(page, limit);
        }
        return list(page, limit, objectWrapper(queryWrapper(), object));
    }

    @Override
    public PageHelper<DOMAIN> page(Integer page, Integer limit) {
        if (XinUtil.isNull(page) && XinUtil.isNull(limit)) {
            return PageHelper.create(1, super.count(), super.count(), 1, super.list());
        }
        return list(page, limit, null);
    }

    @Override
    public PageHelper<DOMAIN> pageSearch(Integer page, Integer limit, DOMAIN domain) {
        if (XinUtil.isNull(domain)) {
            return page(page, limit);
        }
        return list(page, limit, searchWrapper(queryWrapper(), domain));
    }

    @Override
    public PageHelper<DOMAIN> pageForms(Integer page, Integer limit, List<SearchForm> forms) {
        if (XinUtil.isNull(forms)) {
            return page(page, limit);
        }
        return list(page, limit, formsWrapper(queryWrapper(), forms));
    }


    @Override
    public PageHelper<DOMAIN> pageSearchForms(Integer page, Integer limit, DOMAIN domain, List<SearchForm> forms) {
        if (XinUtil.isNull(forms)) {
            return pageSearch(page, limit, domain);
        }
        if (XinUtil.isNull(domain)) {
            return pageForms(page, limit, forms);
        }
        return list(page, limit, searchFormsWrapper(queryWrapper(), domain, forms));
    }

    @Override
    public Class<?> getDomainClass() {
        return domainClass;
    }

    protected PageHelper<DOMAIN> list(Integer page, Integer limit, QueryWrapper<DOMAIN> wrapper){
        if (XinUtil.isNull(page)) {
            page = 0;
        } if (XinUtil.isNull(limit)) {
            limit = 10;
        }
        Page<DOMAIN> domainPage = new Page<>(page, limit);
        IPage<DOMAIN> data = baseMapper.selectPage(domainPage, wrapper);
        return PageHelper.create(page, limit, data.getTotal(), data.getPages(), data.getRecords());
    }

    protected QueryWrapper<DOMAIN> searchFormsWrapper(QueryWrapper<DOMAIN> wrapper, DOMAIN domain, List<SearchForm> forms){
        return formsWrapper(searchWrapper(wrapper, domain), forms);
    }

    protected QueryWrapper<DOMAIN> objectWrapper(QueryWrapper<DOMAIN> wrapper, JSONObject object){
        List<Field> fields = XinUtil.getFieldList(domainClass);
        for (Field field : fields) {
            field.setAccessible(true);
            Object o = object.get(field.getName());
            if (XinUtil.noNull(o)) {
                wrapper.like(field.getName(), o);
            }
            Object startDate = object.get("startDate-" + field.getName());
            Object endDate = object.get("endDate-" + field.getName());
            if (XinUtil.noNull(startDate)) {
                wrapper.ge(field.getName(), startDate);
            }
            if (XinUtil.noNull(endDate)) {
                wrapper.le(field.getName(), endDate);
            }
            // 过滤子节点
            if (XinUtil.equal(field.getName(), "parentId")) {
                wrapper.isNull("parentId");
            }
        }
        return wrapper;
    }

    protected QueryWrapper<DOMAIN> searchWrapper(QueryWrapper<DOMAIN> wrapper, DOMAIN domain){
        List<Field> fields = XinUtil.getFieldList(domainClass);
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                if (XinUtil.isNull(field.get(domain))) {
                    continue;
                }
                wrapper.like(field.getName(), field.get(domain));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                logger.error("\n\n一条数据读取异常\n\n" + e.getMessage());
            }
            // 过滤子节点
            if (XinUtil.equal(field.getName(), "parentId")) {
                wrapper.isNull("parentId");
            }
        }
        return wrapper;
    }

    protected QueryWrapper<DOMAIN> formsWrapper(QueryWrapper<DOMAIN> wrapper, List<SearchForm> forms){
        for (SearchForm form : forms) {
            if (XinUtil.noAllNull(form.getName(), form.getValue())){
                if (XinUtil.isNull(form.getType()) || form.getType() == SearchFormType.PRECISE_QUERY.ordinal()) {
                    wrapper.eq(form.getName(), form.getValue());
                } else if (form.getType() == SearchFormType.FUZZY_QUERY.ordinal()) {
                    wrapper.like(form.getName(), form.getValue());
                }
            }
            if (XinUtil.noNull(form.getType()) && form.getType() == SearchFormType.RANGE_QUERY.ordinal()) {
                if (XinUtil.noNull(form.getValue())) {
                    wrapper.ge(form.getName(), form.getValue());
                }
                if (XinUtil.noNull(form.getValueEnd())) {
                    wrapper.le(form.getName(), form.getValueEnd());
                }
            }
        }
        return wrapper;
    }

    protected LambdaQueryWrapper<DOMAIN> lambdaQueryWrapper() {
        lambdaQueryWrapper = new LambdaQueryWrapper<>();
        return lambdaQueryWrapper;
    }

    protected QueryWrapper<DOMAIN> queryWrapper() {
        queryWrapper = new QueryWrapper<>();
        return queryWrapper;
    }
}
